package com.cy.device.service;

import cn.hutool.json.JSONUtil;
import com.cy.device.cache.CyCabinetCache;
import com.cy.device.common.MqttConstants;
import com.cy.device.common.ResponseBean;
import com.cy.device.config.CyCabinetProperties;
import com.cy.device.model.ConfigSet;
import com.cy.device.model.ControlSet;
import com.cy.device.model.DeviceConfigSet;
import com.cy.device.model.vo.DeviceConfigQueryVO;
import com.cy.device.model.vo.DeviceConfigVO;
import com.cy.device.model.vo.DeviceControlVO;
import com.cy.device.rpc.DeviceFeignClient;
import com.cy.device.rpc.model.DeviceWithProperty;
import com.cy.device.utils.RandomUtil;
import com.cy.swpc.common.domain.model.ResultBean;
import com.cy.swpc.common.systemManage.dto.DeviceCriteria;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;

/**
 * @author: jiangwang
 * @created: 2023/10/25 9:44
 */
@Service
public class DeviceService {

    private final Logger logger = LoggerFactory.getLogger(DeviceService.class);

    public static ConcurrentMap<Integer, DeferredResult<ResponseBean>> resultMap = new ConcurrentHashMap<>();

    @Autowired
    private DeviceFeignClient deviceFeignClient;

    @Autowired
    private CyCabinetProperties cyCabinetProperties;

    @Autowired
    private MqttGateway mqttGateway;

    /**
     * 设备参数设置
     *
     * @param deviceConfigVO 参数信息
     */
    public void setConfig(DeviceConfigVO deviceConfigVO, DeferredResult<ResponseBean> deferredResult) {
        try {
            //生成messageId
            int messageId = RandomUtil.generateRandomNumber();

            // 设置超时事件
            deferredResult.onTimeout(() -> deferredResult.setResult(ResponseBean.error("响应超时!")));

            //当deferredResult完成时（不论是超时还是异常还是正常完成），移除resultMap中相应的key
            deferredResult.onCompletion(() -> {
                logger.info("remove key:{}", messageId);
                resultMap.remove(messageId, deferredResult);
            });

            DeviceConfigSet deviceConfigSet = new DeviceConfigSet();
            //设备编号
            String deviceNo = deviceConfigVO.getDeviceNo();
            BeanUtils.copyProperties(deviceConfigVO, deviceConfigSet);
            ConfigSet configSet = new ConfigSet();
            configSet.setMessageId(messageId);
            configSet.setProperties(deviceConfigSet);
            String cmd = JSONUtil.parseObj(configSet, false).toStringPretty();
            String topic = String.format(MqttConstants.DOWN_DEVICE_SET, deviceNo);
            //发送指令
            mqttGateway.sendToMqtt(topic, 1, cmd);
            logger.info("向智能柜【{}】,发送参数设置指令：{}", deviceNo, cmd);
            resultMap.put(messageId, deferredResult);
        } catch (Exception e) {
            logger.error("向智能机柜发送参数设置指令出错：", e);
        }
    }

    /**
     * 设备参数查询
     *
     * @param deviceNo 设备编号
     */
    public void queryConfig(String deviceNo, DeferredResult<ResponseBean> deferredResult) {
        try {
            //生成messageId
            int messageId = RandomUtil.generateRandomNumber();

            // 设置超时事件
            deferredResult.onTimeout(() -> deferredResult.setResult(ResponseBean.error("响应超时!")));

            //当deferredResult完成时（不论是超时还是异常还是正常完成），移除resultMap中相应的key
            deferredResult.onCompletion(() -> {
                logger.info("remove key:{}", messageId);
                resultMap.remove(messageId, deferredResult);
            });

            DeviceConfigQueryVO configQueryVO = new DeviceConfigQueryVO();
            configQueryVO.setMessageId(messageId);
            String cmd = JSONUtil.parseObj(configQueryVO, false).toStringPretty();
            String topic = String.format(MqttConstants.DOWN_DEVICE_GET, deviceNo);

            //发送指令
            mqttGateway.sendToMqtt(topic, 1, cmd);
            logger.info("向智能柜【{}】,发送参数查询指令：{}", deviceNo, cmd);
            resultMap.put(messageId, deferredResult);
        } catch (Exception e) {
            logger.error("向智能机柜发送参数查询指令出错：", e);
        }
    }

    /**
     * 查询控制项
     *
     * @param deviceNo 设备编号
     */
    public void queryControl(String deviceNo, DeferredResult<ResponseBean> deferredResult) {
        try {
            //生成messageId
            int messageId = RandomUtil.generateRandomNumber();

            // 设置超时事件
            deferredResult.onTimeout(() -> deferredResult.setResult(ResponseBean.error("响应超时!")));

            //当deferredResult完成时（不论是超时还是异常还是正常完成），移除resultMap中相应的key
            deferredResult.onCompletion(() -> {
                logger.info("remove key:{}", messageId);
                resultMap.remove(messageId, deferredResult);
            });

            DeviceConfigQueryVO configQueryVO = new DeviceConfigQueryVO();
            configQueryVO.setMessageId(messageId);

            String cmd = JSONUtil.parseObj(configQueryVO, false).toStringPretty();
            String topic = String.format(MqttConstants.DOWN_DEVICE_CONTROL_QUERY, deviceNo);
            //发送指令
            mqttGateway.sendToMqtt(topic, 1, cmd);
            logger.info("向智能柜【{}】,发送控制项查询指令：{}", deviceNo, cmd);
            resultMap.put(messageId, deferredResult);
        } catch (Exception e) {
            logger.error("向智能机柜发送控制项查询指令出错：", e);
        }
    }

    /**
     * 设置控制项
     *
     * @param deviceControlVO 控制项参数
     */
    public void setControl(DeviceControlVO deviceControlVO, DeferredResult<ResponseBean> deferredResult) {
        try {
            //生成messageId
            int messageId = RandomUtil.generateRandomNumber();

            // 设置超时事件
            deferredResult.onTimeout(() -> deferredResult.setResult(ResponseBean.error("响应超时!")));

            //当deferredResult完成时（不论是超时还是异常还是正常完成），移除resultMap中相应的key
            deferredResult.onCompletion(() -> {
                logger.info("remove key:{}", messageId);
                resultMap.remove(messageId, deferredResult);
            });

            String deviceNo = deviceControlVO.getDeviceNo();
            ControlSet controlSet = new ControlSet();
            controlSet.setMessageId(messageId);
            controlSet.setOptions(deviceControlVO.getOptions());
            String cmd = JSONUtil.parseObj(controlSet, false).toStringPretty();
            String topic = String.format(MqttConstants.DOWN_DEVICE_CONTROL, deviceNo);
            //发送指令
            mqttGateway.sendToMqtt(topic, 1, cmd);
            logger.info("向智能柜【{}】,发送控制项设置指令：{}", deviceNo, cmd);
            resultMap.put(messageId, deferredResult);
        } catch (Exception e) {
            logger.error("向智能机柜发送控制项设置指令出错：", e);
        }
    }

    /**
     * 查询状态
     *
     * @param deviceNo 设备编号
     */
    public void queryStatus(String deviceNo) {
        try {
            //生成messageId
            int messageId = RandomUtil.generateRandomNumber();
            DeviceConfigQueryVO configQueryVO = new DeviceConfigQueryVO();
            configQueryVO.setMessageId(messageId);

            String cmd = JSONUtil.parseObj(configQueryVO, false).toStringPretty();
            String topic = String.format(MqttConstants.DOWN_DEVICE_STATUS_QUERY, deviceNo);
            //发送指令
            mqttGateway.sendToMqtt(topic, 1, cmd);
            logger.info("向智能柜【{}】,发送状态查询指令：{}", deviceNo, cmd);
        } catch (Exception e) {
            logger.error("向智能机柜发送状态查询指令出错：", e);
        }
    }

    /**
     * 获取平台备案设备信息
     */
    public void getDeviceInfo() {
        try {
            DeviceCriteria deviceCriteria = new DeviceCriteria();
            deviceCriteria.setProp1(cyCabinetProperties.getDevType());
            deviceCriteria.setProductCode(cyCabinetProperties.getProductCode());
            ResultBean<List<DeviceWithProperty>> result = deviceFeignClient.getDeviceWithPropertyByCondition(deviceCriteria);
            if (result.getResultCode() != ResultBean.OK) {
                logger.error("获取设备信息失败：{}", result.getResultMessage());
                return;
            }
            CyCabinetCache.CY_CABINET_LIST = result.getData();
            CyCabinetCache.DEV_NO_LIST = result.getData().stream().map(DeviceWithProperty::getDevNo).collect(Collectors.toList());
        } catch (Exception e) {
            logger.error("更新超远智能机柜设备信息异常：", e);
        }
    }

}
